# -*- coding: utf-8 -*-
# created on 2016/9/23


from mathsolver.functions.base import *
from sympy.abc import x, y, c, t
from mathsolver.functions.zhixian.property import GetFangXiang, GetFaXiang
from mathsolver.functions.root.jiefangchen import JieFangChen
from mathsolver.functions.zhixian.base import ZhiXian, default_symbols
from sympy import solve, simplify, symbols, solveset
from mathsolver.functions.zhixian.property import GetZhiXianYiBanShi
from mathsolver.functions.zhixian import GetZhiXianCoeff, GetXieLv001


# 求直线方程:两点式
class SolveFangChengLiangDian(BaseFunction):
    """
    过点M(1,0)和N(0,1)的直线方程是()
    """
    def solver(self, *args):
        if isinstance(args[0], BaseLine):
            name = args[0].printing()
            n1, n2 = args[0].name
            p1 = self.search(n1)
            p2 = self.search(n2)
            point1 = p1.sympify()
            point2 = p2.sympify()
        elif isinstance(args[0], BaseLineName) and len(args) == 3:
            name = args[0].value
            point1 = args[1].sympify()
            point2 = args[2].sympify()
        elif isinstance(args[0], BaseVariable) and len(args) == 2:
            name = args[0].sympify()
            points = args[1].sympify()
            point1 = points[0]
            point2 = points[1]
        elif isinstance(args[0], BasePoints):
            name = ""
            points = args[0].sympify()
            point1 = points[0]
            point2 = points[1]
        elif isinstance(args[0], BasePoint):
            name = ""
            point1 = args[0].sympify()
            point2 = args[1].sympify()
        elif isinstance(args[0], BaseMultiple) and args[0].type == 'Points':
            name = ""
            points = args[0].sympify()
            point1 = points[0]
            point2 = points[1]
            if len(args) == 2 and isinstance(args[1], BaseLineName):
                name = args[1].value
        else:
            name = args[0].value
            points = args[1].sympify()
            point1 = points[0]
            point2 = points[1]
        self.steps.append(["", "由两点式，得"])
        self.steps.append(["%s方程为" % name, "%s" % BaseEq(
            [(y - point1[1]) / (x - point1[0]), (y - point2[1]) / (x - point2[0])]).printing()])
        eq = ((y - point1[1]) * (x - point2[0]) - (x - point1[0]) * (y - point2[1])).expand()
        new_eq = GetZhiXianYiBanShi().solver(BaseEq([eq, S.Zero])).output[0].value
        self.steps.append(["", "整理,得"])
        self.steps.append(["", "%s" % BaseEq(new_eq).printing()])
        self.label.add("求直线方程—两点式")
        self.output.append(BaseZhiXian({"name": "".join(name), "value": new_eq}))
        return self


# 求直线方程:点斜式
class SolveFangChengDianXie(BaseFunction):
    def solver(self, *args):
        point = args[0].sympify()
        xielv = args[1].sympify()
        self.steps.append(["由点斜式，得", BaseEq([y - point[1], xielv * (x - point[0])]).printing()])
        if len(args) == 3:
            self.output.append(BaseZhiXian({"name": args[2].value, "value": [y - point[1], xielv * (x - point[0])]}))
        else:
            self.output.append(BaseZhiXian({"name": "", "value": [y - point[1], xielv * (x - point[0])]}))
        self.label.add("求直线方程-点斜式")
        return self


# 求线段的中垂线
class SolveFangCheng001(BaseFunction):
    def solver(self, *args):
        if len(args) == 2 and isinstance(args[0], BasePoints):
            points = args[0].sympify()
            point1 = points[0]
            point2 = points[1]
            name = args[1].value
        elif len(args) == 3 and isinstance(args[0], BasePoint) and isinstance(args[1], BasePoint):
            point1 = args[0].sympify()
            point2 = args[1].sympify()
            name = args[2].name
        elif len(args) == 1 and isinstance(args[0], (BaseLine, BaseZhiXian)):
            name = args[0].name
            p1, p2 = args[0].name
            point1 = self.search(p1)
            point1 = point1.sympify()
            point2 = self.search(p2)
            point2 = point2.sympify()
        elif len(args) == 3 and isinstance(args[0], BaseVariable):
            name = args[3].sympify()
            point1 = args[0].sympify()
            point2 = args[1].sympify()

        zhongdian = (((point1[0] + point2[0]) / 2).expand().simplify(), ((point1[1] + point2[1]) / 2).expand().simplify())
        if self.search(str(name)):
            zhixian = self.search(str(name))
            step1 = GetZhiXianYiBanShi().solver(zhixian).output[0]
            step2 = GetZhiXianCoeff(step1).solver(step1).output[0]
            xielv = GetXieLv001().solver(step2).output[0].sympify()
            self.output.append(
                BaseZhiXian({"name": name, "value": [(y - zhongdian[1]), -1 / xielv * (x - zhongdian[0] - 1)]}))
        else:
            fa_vector = (point2[0] - point1[0], point2[1] - point1[1])
            eq_left = fa_vector[0] * (x - zhongdian[0]) + fa_vector[1] * (y - zhongdian[1])
            self.steps.append(["", "依题意，得"])
            self.steps.append(["", "中点为(%s, %s)" % (new_latex(zhongdian[0]), new_latex(zhongdian[1]))])
            self.steps.append(["", "所求直线的法方向量为(%s, %s)" % (new_latex(fa_vector[0]), new_latex(fa_vector[1]))])
            self.steps.append(["由点法向式，得", BaseEq([eq_left, S.Zero]).printing()])
            self.output.append(BaseZhiXian({"name": name, "value": [eq_left, S.Zero]}))
            self.label.add("求线段的中垂线方程")
        return self


# 过直线外一点求该直线的垂线方程
class SolveFangCheng002(BaseFunction):
    def solver(self, *args):
        point = args[0].sympify()
        stepsolver = GetZhiXianYiBanShi().solver(args[1])
        stepsolver = GetZhiXianCoeff().solver(stepsolver.output[0])
        fangxiang_vector = GetFangXiang().solver(stepsolver.output[0]).output[0].value['value']
        left = fangxiang_vector[0] * x + fangxiang_vector[1] * y + c
        self.steps.append(["", "设所求直线方程为 %s = %s, 则" % (new_latex(left), new_latex(S.Zero))])
        new_left = left.subs({x: point[0], y: point[1]})
        self.steps.append(["", BaseEq([new_left, S.Zero]).printing()])
        stepsolver = JieFangChen(verbose=True).solver(BaseEq([new_left, S.Zero]))
        self.label.update(stepsolver.label)
        jie = stepsolver.output[0].value
        new_c = jie[list(jie.keys())[0]].args[0]
        self.steps.append(["解得：", BaseEq([c, new_c]).printing()])
        self.steps.append(
            ["∴ 直线方程为", BaseEq([fangxiang_vector[0] * x + fangxiang_vector[1] * y + new_c, S.Zero]).printing()])
        self.label.add("过直线外一点求该直线的垂线方程")
        self.output.append(
            BaseZhiXian({"name": "", "value": [fangxiang_vector[0] * x + fangxiang_vector[1] * y + new_c, S.Zero]}))
        return self


# 代入方程
class DaiRuFangCheng(BaseFunction):
    def solver(self, *args):
        jie = args[0].sympify()
        eq1 = args[1].sympify()
        symbol = jie.keys()[0]
        value = jie[symbol].args[0]
        f1 = eq1[0] - eq1[1]
        new_f1 = f1.subs({symbol: value})
        self.steps.append(["", "将%s = %s 代入 %s = %s,得" % (new_latex(symbol), new_latex(value),
                                                              new_latex(eq1[0]), new_latex(eq1[1]))])
        self.steps.append(["", BaseEq([new_f1, S.Zero]).printing()])
        if isinstance(args[1], BaseZhiXian):
            self.output.append(BaseZhiXian({"name": "", "value": [new_f1, S.Zero]}))
        elif isinstance(args[1], BaseEq):
            self.output.append(BaseEq([new_f1, S.Zero]))
        return self


# 点在图像上,设点坐标
class PointOnGraphAssume(BaseFunction):
    def solver(self, *args):
        if isinstance(args[0], BasePointName):
            eq = args[1].sympify()
            ans = list(solveset(eq[0] - eq[1], y))[0]
            point = BasePoint({"name": args[0].value, "value": [t, ans.subs({x: t})]})
            self.output.append(point)
            self.steps.append(["设%s" % point.printing(), ""])
        elif isinstance(args[0], BaseVariable):
            eq = args[1].sympify()
            ans = list(solveset(eq[0] - eq[1], y))[0]
            point = BasePoint({"name": args[0].value, "value": [t, ans.subs({x: t})]})
            self.output.append(point)
            self.steps.append(["设%s" % point.printing(), ""])
        self.label.add("点在图像上,设点坐标")
        return self


# 点在图像上，代入方程
class PointOnGraph(BaseFunction):
    def solver(self, *args):
        if isinstance(args[0], BaseSymbolValue):
            jies = args[0].sympify()
            left = jies[x]
            left_value = left.args[0]
            right = jies[y]
            right_value = right.args[0]
            point = [left_value, right_value]
        else:
            point = args[0].sympify()
        eq = args[1].sympify()
        f = (eq[0] - eq[1]).expand().simplify()
        self.steps.append(["", "∵点%s在直线%s上" % (BasePoint({"name": "", "value": [point[0], point[1]]}).printing(), BaseEq(eq).printing())])
        xx, yy = symbols("xx,yy")
        new_f1 = f.subs({x: xx, y: yy})
        new_f = new_f1.subs({xx: point[0], yy: point[1]})
        self.steps.append(["", "∴ %s" % BaseEq([new_f, S.Zero]).printing()])
        self.output.append(BaseEq([new_f, S.Zero]))
        if isinstance(args[1], BasePartial):
            cond = args[1].cond
            cond.subs({x: xx, y: yy})
            cond.subs({xx: point[0], yy: point[1]})
            self.steps.append(["", cond.printing()])
            self.output.append(cond)
        self.label.add("点在图像上，代入方程")
        return self


# 过直线外一点求该直线的平行线方程
class SolveFangCheng003(BaseFunction):
    def solver(self, *args):
        point = args[0].sympify()
        faxiang_vector = GetFaXiang().solver(args[1]).output[0].value
        left = faxiang_vector[0] * x + faxiang_vector[1] * y + c
        self.steps.append(["", "设所求直线方程为 %s = %s, 则" % (new_latex(left), new_latex(S.Zero))])
        new_left = left.subs({x: point[0], y: point[1]})
        self.steps.append(["", BaseEq([new_left, S.Zero]).printing()])
        stepsolver = JieFangChen(verbose=True).solver(BaseEq([new_left, S.Zero]))
        self.label.update(stepsolver.label)
        jie = stepsolver.output[0].value
        new_c = jie[jie.keys()[0]].args[0]
        self.steps.append(["解得：", BaseEq([c, new_c]).printing()])
        self.steps.append(
            ["∴ 直线方程为", BaseEq([faxiang_vector[0] * x + faxiang_vector[1] * y + new_c, S.Zero]).printing()])
        self.label.add("过直线外一点求该直线的平行线方程")
        return self


# 求截距相等的直线方程
class SolveFangCheng004(BaseFunction):
    def solver(self, *args):
        name = args[0].value
        zhixian = self.search(name)
        zhixian = zhixian.sympify()
        zhixian_x_offset = ZhiXian(BaseEq(zhixian)).xOffset.sympify()
        zhixian_y_offset = ZhiXian(BaseEq(zhixian)).yOffset.sympify()
        self.steps.append(["", "∴直线%s在x轴上的截距为%s" % (new_latex(name), new_latex(zhixian_x_offset))])
        self.steps.append(["", "∴直线%s在y轴上的截距为%s" % (new_latex(name), new_latex(zhixian_y_offset))])
        symbol = list((zhixian[0] - zhixian[1]).free_symbols.difference([x, y]))[0]
        target_symbol = list((zhixian[0] - zhixian[1]).free_symbols.difference([x, y]))[1]
        eq = zhixian_x_offset - zhixian_y_offset
        self.steps.append(["由截距相等，得", BaseEq([zhixian_x_offset, zhixian_y_offset]).printing()])
        answer = solve(eq, symbol)
        if len(answer) == 1:
            self.steps.append(["", "解得：%s = %s" % (new_latex(symbol), new_latex(answer[0]))])
            new_zhixian_left = simplify(zhixian[0].subs({symbol: answer[0]}) / target_symbol)
            new_zhixian_right = simplify(zhixian[1].subs({symbol: answer[0]}) / target_symbol)
            new_zhixian = [new_zhixian_left, new_zhixian_right]
            self.steps.append(["将%s = %s代入方程，化简得" % (new_latex(symbol), new_latex(answer[0])),
                               BaseZhiXian({"name": name, "value": new_zhixian}).printing()])
            self.output.append(BaseZhiXian({"name": name, "value": new_zhixian}))
        elif len(answer) == 2:
            self.steps.append(["", "解得：%s = %s 或 %s = %s" % (new_latex(symbol), new_latex(answer[0]), new_latex(symbol), new_latex(answer[1]))])
            new_zhixian_left1 = simplify(zhixian[0].subs({symbol: answer[0]}) / target_symbol)
            new_zhixian_right1 = simplify(zhixian[1].subs({symbol: answer[0]}) / target_symbol)
            new_zhixian1 = [new_zhixian_left1, new_zhixian_right1]
            new_zhixian_left2 = simplify(zhixian[0].subs({symbol: answer[1]}) / target_symbol)
            new_zhixian_right2 = simplify(zhixian[1].subs({symbol: answer[1]}) / target_symbol)
            new_zhixian2 = [new_zhixian_left2, new_zhixian_right2]
            self.steps.append(["将%s = %s代入方程，化简得" % (new_latex(symbol), new_latex(answer[0])),
                               BaseZhiXian({"name": name, "value": new_zhixian1}).printing()])
            self.steps.append(["将%s = %s代入方程，化简得" % (new_latex(symbol), new_latex(answer[1])),
                               BaseZhiXian({"name": name, "value": new_zhixian2}).printing()])
            self.output.append(BaseZhiXians([{"name": name, "value": new_zhixian1},
                                             {"name": name, "value": new_zhixian2}]))
        self.label.add("已知直线上的点求截距相等的直线方程")
        return self


class FangCheng001(BaseFunction):
    def solver(self, *args):
        eq = args[1].sympify()
        self.steps.append(["", "∵ 点在直线%s = %s上" % (new_latex(eq[0]), new_latex(eq[1]))])
        x_axis = t
        f = (eq[0] - eq[1]).expand().simplify()
        a, h = f.as_independent(y)
        f_expr = a / (-h).coeff(-h)
        y_axis = f_expr.subs({x: x_axis})
        self.steps.append(["", "∴ 设点的坐标为(%s, %s)" % (new_latex(x_axis), new_latex(y_axis))])
        self.output.append(BasePoint([x_axis, y_axis]))
        return self


# 已知直线的法向量，直线上一点，求直线方程
class SolveFangCheng006(BaseFunction):
    def solver(self, *args):
        if len(args) == 3 and isinstance(args[0], BaseLineName):
            name = args[0].value
            fa_vector = args[1].sympify()
            point = args[2].sympify()
        elif len(args) == 3 and isinstance(args[0], BaseLine):
            name = "".join(args[0].name)
            fa_vector = args[1].sympify()
            point = args[2].sympify()
        elif len(args) == 3 and isinstance(args[0], BaseZhiXian):
            name = args[0].name
            fa_vector = args[1].sympify()
            point = args[2].sympify()
        elif len(args) == 2 and isinstance(args[0], BaseVector):
            name = ""
            fa_vector = args[0].value['value']
            point = args[1].sympify()
        left = fa_vector[0] * (x - point[0]) + fa_vector[1] * (y - point[1])
        self.steps.append(["由直线的点法向式，得", BaseZhiXian({"name": "", "value": [left, S.Zero]}).printing()])
        self.output.append(BaseZhiXian({"name": name, "value": [left, S.Zero]}))
        self.label.add("求直线方程--点法向式")
        return self


# 待定系数法求直线方程
class LineUndeterminedCoefficients(BaseFunction):
    def solver(self, *args):
        if len(args) == 2 and isinstance(args[0], BaseVariable):
            name = args[0].value
            point = args[1].sympify()
            eq = self.search(name)
            eq = eq.sympify()
        elif len(args) == 2 and isinstance(args[0], BasePoint):
            name = ""
            point = args[0].sympify()
            eq = args[1].sympify()
        symx, symy = default_symbols(eq[0] - eq[1])
        expr = eq[0] - eq[1]
        new_expr = expr.subs({symx: point[0], symy: point[1]})
        step1 = JieFangChen().solver(BaseEq([new_expr, S.Zero]))
        self.steps += step1.steps
        jie = step1.output[0].value
        jie_keys = list(jie.keys())[0]
        answer = jie[jie_keys].args[0]
        new_eq = [eq[0].subs({jie_keys: answer}), eq[1].subs({jie_keys: answer})]
        self.steps.append(["", "方程为 %s" % (BaseZhiXian({"name": name, "value": new_eq}).printing())])
        self.output.append(BaseZhiXian({"name": name, "value": new_eq}))
        return self


# 求直线条数
class ZhiXianNumbers(BaseFunction):
    def solver(self, *args):
        zhixians = args[0].sympify()
        num = len(zhixians)
        self.steps.append(["", "∴直线的条数为%s" % (new_latex(num))])
        self.output.append(BaseValue(num))
        self.label.add("求直线的条数")
        return self


if __name__ == '__main__':
    pass
